/*
 * Contains tools for creating non-atomic obstacle structures,
 * as well as templates for more sophisticated structures.
 * 
 */

//Data for nonplayer entities in the game
var obstacleXML = [
	//{ang:0, orb:1, d:1, w:50, h:50, sprite:playerSprite}
];

//A JSON object representing the non-position properties of the standard obstacle
//Enemy objects contain a variable called control that defines specific qualities
//Regarding their sight cones and their behavior
var STDOB = {width:100, height:50, sprite:obstacleSprite, type:"obstacle"};
var STDEN = {width:100, height:87, sprite:enemySprite, type:"guard"};
var UPEN = {width:87, height:100, sprite:enemySprite, type:"guard", control:"up-narrow-3"};
var FRONTEN = {width:100, height:87, sprite:enemySprite, type:"guard", control:"front-normal-2"};
var BACKEN = {width:100, height:87, sprite:enemySprite, type:"guard", control:"back-normal-2"};
var DOWNEN = {width:87, height:100, sprite:enemySprite, type:"guard", control:"down-narrow-3"};
var CHECK = {width:50, height:50, sprite:checkpointSprite, type:"checkpoint"};
var BILL1 = {width:400, height:300, sprite:bill1Sprite, type:"billboard"};
var BILL2 = {width:400, height:300, sprite:bill2Sprite, type:"billboard"};
var BILL3 = {width:400, height:300, sprite:bill3Sprite, type:"billboard"};
var BILL4 = {width:400, height:300, sprite:bill4Sprite, type:"billboard"};
var BILL5 = {width:400, height:300, sprite:bill5Sprite, type:"billboard"};
var BILL6 = {width:400, height:300, sprite:bill6Sprite, type:"billboard"};
var BILL7 = {width:400, height:300, sprite:bill7Sprite, type:"billboard"};
var BILL8 = {width:400, height:300, sprite:bill8Sprite, type:"billboard"};
var SIGN1 = {width:400, height:276, sprite:sign1Sprite, type:"sign"};
var SIGN2A = {width:200, height:138, sprite:sign2aSprite, type:"sign"};
var SIGN2B = {width:200, height:138, sprite:sign2bSprite, type:"sign"};
var SIGN3 = {width:300, height:207, sprite:sign3Sprite, type:"sign"};
var SIGN4 = {width:400, height:276, sprite:sign4Sprite, type:"sign"};
var SIGN5 = {width:400, height:276, sprite:sign5Sprite, type:"sign"};
var TCLOGO = {width:50, height:50, sprite:logoSprite, type:"sign"};

//Template string for custom entity creation
var ENEMY_TEMPLATE = ' {width:50, height:50, sprite:enemySprite, type:"guard", control:"';

//Important directional constants for level design, representing their namesake directions
var NORTH = 0;
var NORTHEAST = Math.PI/4;
var EAST = Math.PI/2;
var SOUTHEAST = Math.PI*(3/4);
var SOUTH = Math.PI;
var SOUTHWEST = Math.PI*(5/4);
var WEST = Math.PI*(3/2);
var NORTHWEST = Math.PI*(7/4);

TWOPI = 2*Math.PI;
PI = Math.PI;

//Symbolic names used for level design
var TOP_ORBIT = ORBIT_COUNT - 1;
var BOTTOM_ORBIT = 0;
var NOARGS = "";

/*
 * Creates an entity of a given type with a given angular position
 * going in a given direction. If there is an entity in the way of the
 * new entity, the original entity is removed to be replaced by the new 
 * one.
 */
function createEntity(orbit, direction, angle, obj){
	var JSONObj = parseEntity(obj);
	if(JSONObj.type == "obstacle"){
		var rndnum = parseInt(Math.min(Math.random()*4, 3));
		var spr = obstacleSprite[rndnum];
		var newEntity = new Entity(angle, orbit, direction, JSONObj.width, JSONObj.height, spr);
		obstacles.push(newEntity);
	}else if(JSONObj.type == "guard"){
		var controlVars = JSONObj.control.split("-");
		var guardAngle, guardRadius, guardLookAngle;
		var spr;
		switch(controlVars[0])
		{
			case "up":		guardLookAngle = 0;
							spr = enemySprite2;
							break;
			case "front":	if(direction > 0){guardLookAngle = Math.PI/2;}
							else if(direction < 0){guardLookAngle = (-1)*Math.PI/2;}
							spr = enemySprite;
							break;
			case "back": 	if(direction > 0){guardLookAngle = (-1)*Math.PI/2;}
							else if(direction < 0){guardLookAngle = Math.PI/2;}
							spr = enemySprite3;
							break;
			case "down":	guardLookAngle = Math.PI;
							spr = enemySprite4;
							break;
			default:		console.log("Error in Obstacle.createLine(): invalid value in control[0]");
		}
		
		switch(controlVars[1])
		{
			case "narrow": 	guardAngle = Math.PI/8;
							break;
			case "normal": 	guardAngle = Math.PI/6;
							break;
			case "wide": 	guardAngle = Math.PI/4;
							break;
			default:		console.log("Error in Obstacle.createLine(): invalid value in control[1]");
		}
		
		guardRadius = (parseInt(controlVars[2])+1/2)*ORBIT_DISTANCE;
		var newEntity = new Entity(angle, orbit, direction, JSONObj.width, JSONObj.height, spr);
		newEntity = addGuardProperties(newEntity, guardRadius, guardAngle, guardLookAngle, false);
		enemies.push(newEntity);
	}else if(JSONObj.type == "checkpoint"){
		var newEntity = new Entity(angle, orbit, direction, JSONObj.width, JSONObj.height, JSONObj.sprite);
		checkpoints.push(newEntity);
	}else if(JSONObj.type == "billboard" || JSONObj.type == "sign"){
		var newEntity = new Entity(angle, orbit, direction, JSONObj.width, JSONObj.height, JSONObj.sprite);
		scenery.push(newEntity);
	}else{
		console.log("Error in Obstacles.createEntity(): invalid object type "+JSONObj);
		return;
	}
}

/*
 * Creates a line of entities of a given type a certain number long
 * in a given orbit going in a given direction, with a given angular offset.
 * Objects are separated by a given pixel count. A separation of zero spaces the
 * objects a distance from each-other equal to their width. obj is a string
 * representing the name of the created object
 */
function createLine(orbit, direction, angle, number, separation, obj){
	var currAngle = angle;
	var angSeparation = Orbit_pixelToAngle(orbit, separation);
	for(var i = 0; i < number; i++){
		createEntity(orbit, direction, currAngle, obj);
		currAngle += angSeparation;
	}
}

/*
 * Creates a ring of entites that wrap around the a given arclength of a given orbit
 * going in a given direction. Paths through are defined by the array "path"
 * which contains beginning (0) and ending (1) angles for the paths through the ring.
 * Ring begins generating from the north position of the orbit, and stops generating at
 * endAng. Obj is a string representing the name of the created object.
 */
function createRingPath(orbit, direction, path, endAng, obj){
	var width;
	if(obj == "obstacle"){
		width = STDOB.width;
	}else{
		width = STDOB.width;
	}
	var lineAngle, entityNum;
	var oldAngle = 0;
	for(var i = 0; i < path.length; i++){
		if(path[i][0] > 2*Math.PI){break;}
		lineAngle = path[i][0] - oldAngle;
		entityNum = parseInt(Orbit_angleToPixel(orbit, lineAngle)/width);
		createLine(orbit, direction, oldAngle, entityNum, width, obj);
		oldAngle = path[i][1];
	}
	if(path[0][0] < 0){
		lineAngle = endAng + path[0][0] - oldAngle;
	}else{
		lineAngle = endAng - oldAngle;
	}
	entityNum = parseInt(Orbit_angleToPixel(orbit, lineAngle)/width);
	createLine(orbit, direction, oldAngle, entityNum, width, obj);
}

/*
 * Creates a ring of entities that wrap around the entirety of a given orbit
 * going in a given direction, with at least a given pixel offset between each entity,
 * with the "first" entity in the ring with a given angular offset.
 * Obj is a string representing the name of the created object
 */
function createRingOffset(orbit, direction, offset, angle, endAng, obj){
	var orbitLength = Orbit_angleToPixel(orbit, endAng - angle);
	var entityNum;
	if(offset == 0){
		var width;
		if(obj == "obstacle"){
			width = STDOB.width;
		}else if(obj == "checkpoint"){
			width = STDOB.width;
		}else{
			width = STDEN.width;
		}
		entityNum = parseInt(orbitLength/width);
	}else{
		entityNum = parseInt(orbitLength/offset);
	}
	createLine(orbit, direction, angle, entityNum, offset, obj);
}


//Creates all of the obstacles and enemies on the map
function Obstacles_createObstacles(){
	//createOldLevel();
	createLevel1();
	//Creates the obstacles out of the obstacleXML array, which will
	//One day be an XML file and accessed as such
	for(var i = 0; i < obstacleXML.length; i++){
		pushval = new Entity(obstacleXML[i].ang, obstacleXML[i].orb, obstacleXML[i].d,
							 obstacleXML[i].w, obstacleXML[i].h,  obstacleXML[i].sprite);
		obstacles.push(pushval);
		console.log("obstacle added: "+obstacles[i].angle+", "+obstacles[i].orbit);
	}
}

/*
 * Takes a given string and parses it as a series of paths, returning
 * the array corresponding to it, or throwing a fit if not in the right format.
 * strings should be of the form (without outer most quote marks)
 * "angle:width, angle:width, ... , angle:width"
 */

function createPathString(orbit, str){
	var retval = [];
	var outerSplit = str.split(",");
	for(var i = 0; i < outerSplit.length; i++){
		var innerSplit = outerSplit[i].split(":");
		innerSplit[0] = innerSplit[0].replace(" ", "");
		var angle = parseAngle(innerSplit[0]);
		var width = Orbit_pixelToAngle(orbit, parseInt(innerSplit[1]) + player.width*(2-difficulty))/2;
		retval.push([angle - width, angle + width]);
	}
	return retval;
}

/*
 * Takes a given nx2 array and parses it as a series of paths,
 * returning the array corresponding to it.
 * arrays should be of the form [[angle, width]. [angle, width] ... ]
 * with width in pixels
 */
function createPathArray(orbit, array){
	var retval = []; var width;
	for(var i = 0; i < array.length; i++){
		width = Orbit_pixelToAngle(orbit, array[i][1]  + player.width*(2-difficulty))/2;
		retval.push([array[i][0] - width, array[i][0] + width]);
	}
	return retval;
}

//Parses a given value or position name as its corresponding float
function parseAngle(angle){
	var retval;
	switch (angle){
		case "NORTH": 		retval = NORTH;
							break;
		case "NORTHEAST": 	retval = NORTHEAST;
							break;
		case "EAST": 		retval = EAST;
							break;
		case "SOUTHEAST": 	retval = SOUTHEAST;
							break;
		case "SOUTH": 		retval = SOUTH;
							break;
		case "SOUTHWEST": 	retval = SOUTHWEST;
							break;
		case "WEST": 		retval = WEST;
							break;
		case "NORTHWEST": 	retval = NORTHWEST;
							break;
		default:			retval = parseFloat(angle);
							break;				
	}
	return retval;
}

/*
 * Parses a string and uses it to create some sort of entity, either by associating
 * it with a preset entity JSON or by creating a new one. returns the JSON found or created.
 * All custom string representations of JSONs should obey the following syntax:
 * 		width:widthVal, height:heightVal, sprite:spriteVal, type:typename, control:controlVal
 */

function parseEntity(string){
	var retval;
	switch(string)
	{
		case "obstacle": 	retval = STDOB;
							break;
		case "upGuard": 	retval = UPEN;
							break;
		case "downGuard": 	retval = DOWNEN;
							break;
		case "frontGuard": 	retval = FRONTEN;
							break;
		case "backGuard": 	retval = BACKEN;
							break;
		case "checkpoint": 	retval = CHECK;
							break;
		case "bill1": 		retval = BILL1;
							break;
		case "bill2": 		retval = BILL2;
							break;
		case "bill3": 		retval = BILL3;
							break;
		case "bill4": 		retval = BILL4;
							break;
		case "bill5": 		retval = BILL5;
							break;
		case "bill6": 		retval = BILL6;
							break;
		case "bill7": 		retval = BILL7;
							break;
		case "bill8": 		retval = BILL8;
							break;
		case "sign1": 		retval = SIGN1;
							break;
		case "sign2a": 		retval = SIGN2A;
							break;
		case "sign2b": 		retval = SIGN2B;
							break;
		case "sign3": 		retval = SIGN3;
							break;
		case "sign4": 		retval = SIGN4;
							break;
		case "sign5": 		retval = SIGN5;
							break;
		default:			retval = parseEntityHelper(string);				
	}
	return retval;
}

//Helper function for parseEntity that handles the default case
function parseEntityHelper(string){
	var parseString = ENEMY_TEMPLATE+string+'"} ';
	return JSON.parse(parseString);
}

//Removes all obstacles overlapping with enemy objects
function trimOverlap(){
	for(var j = 0; j < enemies.length; j++){
		for(var i = 0; i < obstacles.length; i++){
			if(enemies[j].checkCollision(obstacles[i])){
				obstacles.splice(i, 1);
			}
		}
	}
}

//Shortcut to Orbit_pixelToAngle
function PTA(orbit, length){
	return Orbit_pixelToAngle(orbit, length);
}

